package controller

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"yuanfilesys/dao"
	"yuanfilesys/utils"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// CreateFolder 创建文件夹
func CreateFolder(c *gin.Context) {
	user := c.MustGet("user").(dao.User)

	//根据父文件node的id进行创建
	parentID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件夹ID"})
		return
	}
	//获取文件夹名
	folderName := c.Query("name")
	if folderName == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "文件夹名称不能为空"})
		return
	}
	//获取父节点
	var parent dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", parentID, user.ID).First(&parent).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "父文件夹不存在"})
		return
	}
	//判断父节点是否为文件夹
	if !parent.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "父路径不是文件夹"})
		return
	}
	//防止重名
	newName := utils.GetAvailableName(folderName, parentID, user.ID, true)

	// 构建新文件夹结构体
	newFolder := dao.FileNode{
		Name:      newName,
		Path:      utils.ConstructPath(parent.Path, newName),
		IsDir:     true,
		UserID:    user.ID,
		ParentID:  uint(parentID),
		CreatedAt: utils.GetCurrentTime(),
		UpdatedAt: utils.GetCurrentTime(),
	}

	// 事务处理：确保数据库和文件系统操作的一致性
	err = dao.DB.Transaction(func(tx *gorm.DB) error {
		// 写入数据库
		if err := tx.Create(&newFolder).Error; err != nil {
			return fmt.Errorf("创建文件夹记录失败: %v", err)
		}

		// 构建物理路径 (格式: data/id_username/path)
		storagePath := utils.BuildStoragePath(&user, newFolder.Path)

		// 在硬盘上创建文件夹
		if err := os.MkdirAll(storagePath, 0755); err != nil {
			// 回滚数据库操作
			tx.Rollback()
			return fmt.Errorf("创建物理文件夹失败: %v", err)
		}

		return nil
	})

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, newFolder)
}

// UploadFile 上传文件
func UploadFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	//上次至哪个文件夹下
	parentID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件夹ID"})
		return
	}

	// 获取上传的文件
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "缺少文件"})
		return
	}

	// 获取父文件夹和用户
	var parent dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", parentID, user.ID).First(&parent).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "父文件夹不存在"})
		return
	}

	//判断父是不是文件夹
	if !parent.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "父路径不是文件夹"})
		return
	}

	// 处理文件名
	fileName := file.Filename
	newName := utils.GetAvailableName(fileName, parentID, user.ID, false)

	// 创建文件节点
	filePath := utils.ConstructPath(parent.Path, newName)
	fileNode := dao.FileNode{
		Name:      newName,
		Path:      filePath,
		IsDir:     false,
		Size:      file.Size,
		UserID:    user.ID,
		ParentID:  uint(parentID),
		Version:   1,
		CreatedAt: utils.GetCurrentTime(),
		UpdatedAt: utils.GetCurrentTime(),
	}

	if err := dao.DB.Create(&fileNode).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "创建文件记录失败"})
		return
	}

	// 保存文件到磁盘
	storagePath := utils.GetStoragePath(user.ID, user.Username, filePath)

	if err := utils.SaveFile(c, storagePath); err != nil {
		// 删除文件记录
		dao.DB.Delete(&fileNode)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败"})
		return
	}

	c.JSON(http.StatusCreated, fileNode)
}

// UpdateFile 更新文件 根据文件id进行更新文件
func UpdateFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}

	// 获取上传的文件
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "缺少文件"})
		return
	}

	// 获取文件信息 根据文件id和用户id进行更新
	var fileNode dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&fileNode).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}

	//判断是否是文件夹
	if fileNode.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无法更新文件夹"})
		return
	}

	// 创建新版本
	newVersion := fileNode.Version + 1

	// 保存新版本文件
	storagePath := utils.GetStoragePathWithVersion(user.Username, fileNode.Path, newVersion)
	if err := utils.SaveFile(c, storagePath); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败"})
		return
	}

	// 更新文件记录
	fileNode.Size = file.Size
	fileNode.Version = newVersion
	fileNode.UpdatedAt = utils.GetCurrentTime()

	//进行保存文件
	if err := dao.DB.Save(&fileNode).Error; err != nil {
		// 删除已保存的文件
		utils.DeleteFile(storagePath)
		c.JSON(http.StatusInternalServerError, gin.H{"error": "更新文件记录失败"})
		return
	}
	c.JSON(http.StatusOK, fileNode)
}

// DeleteFile 删除文件或文件夹（支持递归删除非空文件夹）
func DeleteFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}

	// 获取文件信息
	var fileNode dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&fileNode).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}

	// 事务处理确保数据一致性
	err = dao.DB.Transaction(func(tx *gorm.DB) error {
		// 递归删除所有子文件/文件夹（如果是目录）
		if fileNode.IsDir {
			if err := deleteChildren(tx, &user, fileID); err != nil {
				return err
			}
		}

		// 删除磁盘上的文件/文件夹
		storagePath := utils.GetStoragePath(user.ID, user.Username, fileNode.Path)

		if err := utils.DeleteFile(storagePath); err != nil {
			return fmt.Errorf("删除文件失败: %v", err)
		}

		// 删除当前文件记录
		if err := tx.Delete(&fileNode).Error; err != nil {
			return fmt.Errorf("删除文件记录失败: %v", err)
		}
		return nil
	})

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "删除成功"})
}

// 递归删除所有子文件/文件夹
func deleteChildren(tx *gorm.DB, user *dao.User, parentID int) error {
	// 获取所有子节点
	var children []dao.FileNode
	if err := tx.Where("parentid = ? AND userid = ?", parentID, user.ID).Find(&children).Error; err != nil {
		return err
	}

	// 递归删除子文件夹
	for _, child := range children {
		if child.IsDir {
			if err := deleteChildren(tx, user, int(child.ID)); err != nil {
				return err
			}
		}
		// 删除磁盘上的文件/文件夹
		storagePath := utils.BuildStoragePath(user, child.Path)
		// 删除文件
		if err := utils.DeleteFile(storagePath); err != nil {
			return err
		}
		// 删除数据库记录
		if err := tx.Delete(&child).Error; err != nil {
			return err
		}
	}

	return nil
}

// CopyFile 复制文件或文件夹
func CopyFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}

	//dest 表示文件要移动到的目标文件夹 ID
	destParentID, err := strconv.Atoi(c.Query("dest"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的目标文件夹ID"})
		return
	}

	fmt.Println("destParentID", destParentID)
	// 获取源文件信息
	var sourceFile dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&sourceFile).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "源文件不存在"})
		return
	}

	// 获取目标文件夹
	var destParent dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", destParentID, user.ID).First(&destParent).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "目标文件夹不存在"})
		return
	}

	if !destParent.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "目标路径不是文件夹"})
		return
	}

	// 处理名称冲突
	newName := utils.GetAvailableName(sourceFile.Name, destParentID, user.ID, sourceFile.IsDir)
	newPath := utils.ConstructPath(destParent.Path, newName)

	// 复制文件或文件夹
	if sourceFile.IsDir {
		// 复制文件夹
		if err := copyFolder(sourceFile, uint(destParentID), newName, newPath, user.ID); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "复制文件夹失败"})
			return
		}
	} else {
		// 复制文件
		if err := copyFile(sourceFile, uint(destParentID), newName, newPath, user.ID); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "复制文件失败"})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "复制成功"})
}

// MoveFile 移动文件或文件夹
func MoveFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	//获取id号
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}
	destParentID, err := strconv.Atoi(c.Query("dest"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的目标文件夹ID"})
		return
	}
	// 获取源文件信息
	var sourceFile dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&sourceFile).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "源文件不存在"})
		return
	}
	// 获取目标文件夹
	var destParent dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", destParentID, user.ID).First(&destParent).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "目标文件夹不存在"})
		return
	}

	//判断目标路径是不是文件夹
	if !destParent.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "目标路径不是文件夹"})
		return
	}
	// 处理名称冲突
	newName := utils.GetAvailableName(sourceFile.Name, destParentID, user.ID, sourceFile.IsDir)

	//新路径
	newPath := utils.ConstructPath(destParent.Path, newName)

	// 移动文件或文件夹
	if sourceFile.IsDir {
		// 移动文件夹
		if err := moveFolder(sourceFile, uint(destParentID), newName, newPath, user.ID); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "移动文件夹失败"})
			return
		}
	} else {
		tx := dao.DB.Begin()
		// 1. 先获取用户名（用于拼接用户专属目录）
		username := utils.GetUsernameByID(user.ID) // 假设从用户ID获取用户名

		// 2. 生成源文件和目标文件的完整物理路径
		// （基于项目的 data 目录 + 用户名 + 相对路径）
		userDir := fmt.Sprintf("%d_%s", user.ID, username)

		sourceFullPath := filepath.Join("data", userDir, sourceFile.Path)
		destFullPath := filepath.Join("data", userDir, newPath)

		// 移动文件
		if err := utils.RenameFile(sourceFullPath, destFullPath); err != nil {
			// 错误处理
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{"error": "移动文件失败: " + err.Error()})
			return
		}
		fmt.Println(destParentID)
		// 更新数据库中文件的记录

		// 在更新后立即检查影响的行数
		result := tx.Model(&dao.FileNode{}).
			Where("id = ? AND userid = ?", sourceFile.ID, user.ID).
			Updates(map[string]interface{}{
				"parentid": destParentID,
				"path":     newPath,
				"name":     newName,
			})

		fmt.Printf("更新影响的行数: %d\n", result.RowsAffected) // 打印影响的行数
		if result.Error != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{"error": "更新文件记录失败: " + result.Error.Error()})
			return
		}

		// 确保事务最终提交
		if err := tx.Commit().Error; err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{"error": "事务提交失败: " + err.Error()})
			return
		}
	}
	c.JSON(http.StatusOK, gin.H{"message": "文件移动成功"})
}

// 递归更新子文件的路径（当父文件夹路径变更时）
func UpdateChildrenPath(tx *gorm.DB, userID, parentID int, oldParentPath, newParentPath string) error {
	var children []dao.FileNode
	if err := tx.Where("parent_id = ? AND userid = ?", parentID, userID).Find(&children).Error; err != nil {
		return err
	}

	for _, child := range children {
		// 替换子文件路径中的旧父路径为新父路径
		oldChildPath := child.Path

		newChildPath := strings.Replace(oldChildPath, oldParentPath, newParentPath, 1)

		// 更新当前子文件的路径
		if err := tx.Model(&dao.FileNode{}).
			Where("id = ? AND userid = ?", child.ID, userID).
			Update("path", newChildPath).Error; err != nil {
			return err
		}

		// 如果是子文件夹，递归更新其下的文件
		if child.IsDir {
			if err := UpdateChildrenPath(tx, userID, int(child.ID), oldParentPath, newParentPath); err != nil {
				return err
			}
		}
	}
	return nil
}

// RenameFile重命名文件或文件夹
func RenameFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	//获取要更改的文件id
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}

	newName := c.Query("name")
	if newName == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "新名称不能为空"})
		return
	}

	// 获取文件信息 查看这个文件是否属于该用户
	var fileNode dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&fileNode).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}

	// 检查新名称是否已存在
	var siblings []dao.FileNode
	dao.DB.Where("parentid = ? AND userid = ? AND name = ? AND id != ?",
		fileNode.ParentID, user.ID, newName, fileID).Find(&siblings)
	if len(siblings) > 0 {
		c.JSON(http.StatusConflict, gin.H{"error": "名称已存在"})
		return
	}

	// 构建新路径
	parentPath := "/"
	if fileNode.ParentID != 0 {
		var parent dao.FileNode
		if err := dao.DB.Where("id = ? AND userid = ?", fileNode.ParentID, user.ID).First(&parent).Error; err == nil {
			parentPath = parent.Path
		}
	}
	newPath := utils.ConstructPath(parentPath, newName)

	// 重命名文件或文件夹
	if fileNode.IsDir {
		// 重命名文件夹及其所有子项
		if err := renameFolder(fileNode, newName, newPath, user.ID); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "重命名文件夹失败"})
			return
		}
	} else {
		// 重命名文件
		oldStoragePath := utils.GetStoragePath(user.ID, user.Username, fileNode.Path)

		newStoragePath := utils.GetStoragePath(user.ID, user.Username, newPath)

		//将名称进行更改
		if err := utils.RenameFile(oldStoragePath, newStoragePath); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "重命名文件失败"})
			return
		}

		// 更新文件记录
		fileNode.Name = newName
		fileNode.Path = newPath
		if err := dao.DB.Save(&fileNode).Error; err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "更新文件记录失败"})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{"message": "重命名成功"})
}

// GetFileInfo 获取文件信息
func GetFileInfo(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}

	// 获取文件信息
	var fileNode dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&fileNode).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}

	c.JSON(http.StatusOK, fileNode)
}

// ListFiles 列出文件夹内容
func ListFiles(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	//转为int
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件夹ID"})
		return
	}
	// 获取文件夹信息
	log.Println(fileID)
	log.Println(user.ID)

	var folder dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ? AND isdir = ?", fileID, user.ID, true).First(&folder).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件夹不存在"})
		return
	}

	// 获取子文件和文件夹
	var children []dao.FileNode
	dao.DB.Where("parentid = ? AND userid = ?", fileID, user.ID).Find(&children)

	//返回成功码和结果
	c.JSON(http.StatusOK, children)
}

// DownloadFile 下载文件
func DownloadFile(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	//从 HTTP 请求的 URL 路径中获取名为 file_id 的参数值
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}
	fmt.Println("文件id", fileID)
	// 获取文件信息 文件id和用户id就是组合
	var fileNode dao.FileNode

	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&fileNode).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}

	fmt.Println("hello yuan")
	//判断文件是否是文件夹
	if fileNode.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无法下载文件夹"})
		return
	}

	// 获取文件路径
	storagePath := utils.GetStoragePath(user.ID, user.Username, fileNode.Path)

	// 检查文件是否存在
	if !utils.FileExists(storagePath) {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}
	// 下载文件
	c.File(storagePath)
}

// DownloadFileVersion 下载历史版本
func DownloadFileVersion(c *gin.Context) {
	user := c.MustGet("user").(dao.User)
	fileID, err := strconv.Atoi(c.Param("file_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件ID"})
		return
	}

	verNum, err := strconv.Atoi(c.Param("ver_num"))
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的版本号"})
		return
	}

	// 获取文件信息
	var fileNode dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", fileID, user.ID).First(&fileNode).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
		return
	}

	if fileNode.IsDir {
		c.JSON(http.StatusBadRequest, gin.H{"error": "文件夹没有版本"})
		return
	}

	if verNum < 1 || verNum > fileNode.Version {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的版本号"})
		return
	}

	// 获取文件路径
	storagePath := utils.GetStoragePathWithVersion(user.Username, fileNode.Path, verNum)

	// 检查文件是否存在
	if !utils.FileExists(storagePath) {
		c.JSON(http.StatusNotFound, gin.H{"error": "版本文件不存在"})
		return
	}

	// 下载文件
	c.File(storagePath)
}

// 辅助函数：复制文件夹
func copyFolder(source dao.FileNode, destParentID uint, newName string, newPath string, userID uint) error {
	// 创建新文件夹
	newFolder := dao.FileNode{
		Name:      newName,
		Path:      newPath,
		IsDir:     true,
		UserID:    userID,
		ParentID:  destParentID,
		CreatedAt: utils.GetCurrentTime(),
		UpdatedAt: utils.GetCurrentTime(),
	}

	if err := dao.DB.Create(&newFolder).Error; err != nil {
		return err
	}
	// 获取源文件夹的子项
	var children []dao.FileNode
	dao.DB.Where("parentid = ? AND userid = ?", source.ID, userID).Find(&children)

	// 递归复制子项
	for _, child := range children {
		if child.IsDir {
			childNewPath := utils.ConstructPath(newPath, child.Name)
			if err := copyFolder(child, newFolder.ID, child.Name, childNewPath, userID); err != nil {
				return err
			}
		} else {
			if err := copyFile(child, newFolder.ID, child.Name, utils.ConstructPath(newPath, child.Name), userID); err != nil {
				return err
			}
		}
	}
	return nil
}

// 辅助函数：复制文件
func copyFile(source dao.FileNode, destParentID uint, newName string, newPath string, userID uint) error {
	// 创建新文件记录
	newFile := dao.FileNode{
		Name:      newName,
		Path:      newPath,
		IsDir:     false,
		Size:      source.Size,
		UserID:    userID,
		ParentID:  destParentID,
		Version:   source.Version,
		CreatedAt: utils.GetCurrentTime(),
		UpdatedAt: utils.GetCurrentTime(),
	}

	if err := dao.DB.Create(&newFile).Error; err != nil {
		return err
	}

	// 复制文件内容
	sourcePath := utils.GetStoragePath(userID, utils.GetUsernameByID(userID), source.Path)
	destPath := utils.GetStoragePath(userID, utils.GetUsernameByID(userID), newPath)

	return utils.CopyFile(sourcePath, destPath)
}

// 辅助函数：移动文件夹
func moveFolder(source dao.FileNode, destParentID uint, newName string, newPath string, userID uint) error {
	// 开始事务
	tx := dao.DB.Begin()
	if tx.Error != nil {
		return tx.Error
	}

	// 更新文件夹记录
	source.Name = newName
	source.Path = newPath
	source.ParentID = destParentID
	source.UpdatedAt = utils.GetCurrentTime()

	if err := tx.Save(&source).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 获取源文件夹的子项
	var children []dao.FileNode
	if err := tx.Where("parentid = ? AND userid = ?", source.ID, userID).Find(&children).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 递归移动子项
	for _, child := range children {
		childNewPath := utils.ConstructPath(newPath, child.Name)
		if child.IsDir {
			if err := moveFolder(child, source.ID, child.Name, childNewPath, userID); err != nil {
				tx.Rollback()
				return err
			}
		} else {
			if err := moveFile(child, source.ID, child.Name, childNewPath, userID); err != nil {
				tx.Rollback()
				return err
			}
			// 更新数据库中文件的记录
			if err := tx.Model(&dao.FileNode{}).
				Where("id = ? AND userid = ?", source.ID, child.ID).
				Updates(map[string]interface{}{
					"parent_id": destParentID, // 更新父文件夹ID
					"path":      newPath,      // 更新完整路径
					"name":      newName,      // 更新名称
				}).Error; err != nil {
				tx.Rollback()
				return err
			}

		}
	}

	return tx.Commit().Error
}

// 辅助函数：移动文件
func moveFile(source dao.FileNode, destParentID uint, newName string, newPath string, userID uint) error {
	// 开始事务
	tx := dao.DB.Begin()
	if tx.Error != nil {
		return tx.Error
	}

	// 更新文件记录
	source.Name = newName
	source.Path = newPath
	source.ParentID = destParentID
	source.UpdatedAt = utils.GetCurrentTime()

	if err := tx.Save(&source).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 移动文件内容
	username := utils.GetUsernameByID(userID)
	//这里有些问题 注意进行更改
	sourcePath := utils.GetStoragePath(userID, username, source.Path)
	//获取存储路径
	destPath := utils.GetStoragePath(userID, username, newPath)

	fmt.Println("yuan1", sourcePath)
	fmt.Println(destPath)

	if err := utils.RenameFile(sourcePath, destPath); err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}

// 辅助函数：重命名文件夹
func renameFolder(folder dao.FileNode, newName string, newPath string, userID uint) error {
	// 开始事务
	tx := dao.DB.Begin()
	if tx.Error != nil {
		return tx.Error
	}
	// 更新文件夹记录
	oldPath := folder.Path
	folder.Name = newName
	folder.Path = newPath
	folder.UpdatedAt = utils.GetCurrentTime()

	if err := tx.Save(&folder).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 获取文件夹的子项
	var children []dao.FileNode
	if err := tx.Where("parentid = ? AND userid = ?", folder.ID, userID).Find(&children).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 递归重命名子项 对其下面的文件和文件夹都要进行修改
	for _, child := range children {
		childNewName := child.Name
		childNewPath := utils.ConstructPath(newPath, childNewName)
		if child.IsDir {
			if err := renameFolder(child, childNewName, childNewPath, userID); err != nil {
				tx.Rollback()
				return err
			}
		} else {
			// 重命名文件
			oldFilePath := utils.ConstructPath(oldPath, child.Name)
			username := utils.GetUsernameByID(userID)
			oldStoragePath := utils.GetStoragePath(userID, username, oldFilePath)
			newStoragePath := utils.GetStoragePath(userID, username, childNewPath)

			if err := utils.RenameFile(oldStoragePath, newStoragePath); err != nil {
				tx.Rollback()
				return err
			}

			// 更新文件记录
			child.Path = childNewPath
			if err := tx.Save(&child).Error; err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	return tx.Commit().Error
}

// 辅助函数：检查是否是子文件夹
// 用于判断某个文件夹（folder）是否位于另一个指定文件夹（parentID）的路径层级中
func isSubFolder(folderID uint, parentID uint, userID uint) bool {
	// 获取文件夹
	var folder dao.FileNode
	if err := dao.DB.Where("id = ? AND userid = ?", folderID, userID).First(&folder).Error; err != nil {
		return false
	}

	// 向上查找父文件夹
	currentID := folder.ParentID
	for currentID != 0 {
		if currentID == parentID {
			return true
		}

		var parent dao.FileNode
		if err := dao.DB.Where("id = ? AND userid = ?", currentID, userID).First(&parent).Error; err != nil {
			break
		}
		//对将当前文件夹往上提一级
		currentID = parent.ParentID
	}

	return false
}
